﻿using DataModel;
using FormatUtil;
using HPSocket;
using HPSocket.Tcp;

using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
 
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SanitationTcpGw
{
    public static class TransDataWorkerHY
    {


        //待转发到省平台数据包列表
        public static Queue<byte[]> _needToTransDataList = new Queue<byte[]>();
        public static string GovIP = ConfigurationManager.AppSettings["HYIP"];
        public static int GovPort = int.Parse(ConfigurationManager.AppSettings["HYPort"]);

   
        public enum AppState
        {
            Starting, Started, Stoping, Stoped, Error
        }
        static private AppState appState = AppState.Stoped;

        static TcpClient client = new TcpClient();

        private static byte[] _cacheBytes;

      
        private static object lsObj = new object();
        private static object conStateObj = new object();
        public static Hashtable yjFs = new Hashtable();

 
        private static Timer pantTimer = null;
        private static Queue<byte[]> _ydByteQ = new Queue<byte[]>();
 
       
        private static string SendEscape(string s)
        {
            string ret = string.Empty;
            string tmp = string.Empty;
            for (int i = 0; i < s.Length / 2; i++)
            {
                tmp = s.Substring(i * 2, 2);
                if (tmp == "7D")
                    ret = ret + "7D01";
                else
                    ret = ret + tmp;
            }
            s = ret;
            ret = string.Empty;
            for (int i = 0; i < s.Length / 2; i++)
            {
                tmp = s.Substring(i * 2, 2);
                if (tmp == "7E")
                    ret = ret + "7D02";
                else
                    ret = ret + tmp;
            }
            return ret;
        }
        public static void Start()
        {
            InitTcpClient();
            pantTimer = new Timer(pantCon, null, 10000, 10000);
          

            for (int i = 0; i < 1; i++)
            {
                Thread trdTcpRecvThread = new Thread(new ThreadStart(ThreadTransDataToGov));
                trdTcpRecvThread.Start();
            }

            Thread ydThread = new Thread(new ThreadStart(ydDataToGov));
            ydThread.Start();
        }

        private static void pantCon(object state)
        {
            try
            {
                AppState appSt = AppState.Stoped;
                lock (conStateObj)
                {
                    appSt = appState;
                }

                if (appSt == AppState.Stoped)
                {
                        AddMsg( " 平台连接断开");
                  
                    if (client.Connect(GovIP, (ushort)GovPort))
                    {
                    
                        AddMsg("平台连接成功");
                        SetAppState(AppState.Started);
                    }

                }
            }
            catch (Exception ex)
            {
                AddMsg(ex.ToString());
            }
        }

 
     

        private static void ydDataToGov()
        {
            while (true)
            {
                try
                {


                    byte[] bs = null;
                    lock (_ydByteQ)
                    {
                        if (_ydByteQ.Count > 0)
                        {
                            bs = _ydByteQ.Dequeue();
                        }
                    }
                    if (bs != null)
                    {
                        HandleOneExsunPackage(bs);
                    }
                    else
                    {
                        Thread.Sleep(5);
                    }
                }
                catch (Exception ex)
                {
                    LogHelp.WriteeLog("", ex.ToString());
                }
            }
        }

        private static void ThreadTransDataToGov()
        {
            Thread.Sleep(10000);
            while (true)
            {
                try
                {
                    byte[] sendData = null;
                 
                    AppState appSt = AppState.Stoped;
                    lock (conStateObj)
                    {
                        appSt = appState;
                    }


                        if (appSt == AppState.Started )
                        {
                            lock (_needToTransDataList)
                            {
                                if (_needToTransDataList.Count > 0)
                                {
                                    sendData = _needToTransDataList.Dequeue();

                                }
                            }

                            if (sendData != null)
                            {
                                if (SendTcpData(sendData))
                                {
                                }
                                else
                                {
                                    lock (_needToTransDataList)
                                    {
                                        _needToTransDataList.Enqueue(sendData);
                                    }
                                }

                            }
                            else
                            {
                                Thread.Sleep(10);
                            }
                        }
                        else
                        {
                            AddMsg("平台连接失败！");
                            
                            Thread.Sleep(10000);
                        }
                   
                }
                catch (Exception ex)
                {
                    AddMsg(ex.ToString());
                    
                }
            }
        }

        #region 初始化TCP客户端
        public static void InitTcpClient()
        {
            try
            {
                SetAppState(AppState.Stoped);
                client.OnPrepareConnect += OnPrepareConnect;
                client.OnConnect += OnConnect;
                client.OnSend +=OnSend;
                client.OnReceive +=OnReceive;
                client.OnClose +=OnClose;

 
                if (client.Connect(GovIP, (ushort)GovPort))
                {
                    SetAppState(AppState.Started);

                    AddMsg(string.Format("$Client Start OK -> ({0}:{1})", GovIP, GovPort));
                }
                else
                {
                    SetAppState(AppState.Stoped);
                    throw new Exception(string.Format("$Client Start Error -> {0}({1})", client.ErrorMessage, client.ErrorCode));
                }
            }
            catch (Exception ex)
            {
                AddMsg(ex.Message);
            }
        }
        #endregion
        static void SetAppState(AppState state)
        {
            lock (conStateObj)
            {
                appState = state;
            }
        }

        static HandleResult OnPrepareConnect(IClient sender, IntPtr socket)
        {
            return HandleResult.Ok;
        }
        static HandleResult OnConnect(IClient sender)
        {
            // 已连接 到达一次
            SetAppState(AppState.Started);
          

            return HandleResult.Ok;
        }

        static HandleResult OnSend(IClient sender, byte[] bytes)
        {
            // 客户端发数据了
            //AddMsg(string.Format(" > [{0},OnSend] -> ({1} bytes)", sender.ConnectionId, bytes.Length));

            return HandleResult.Ok;
        }

        static HandleResult OnReceive(IClient sender, byte[] bytes)
        {
            // 数据到达了
            try
            {
                if (bytes.Length > 0)
                {
                    HandlePackages(bytes);
                    //Console.WriteLine(GwUtil.BytesToHex(bytes));
                }
            }
            catch (Exception ex)
            {
                AddMsg(ex.ToString());
              
            }

            return HandleResult.Ok;

        }

        static HandleResult OnClose(IClient sender, SocketOperation enOperation, int errorCode)
        {
            if (errorCode == 0)
            {
                // 连接关闭了
                AddMsg(string.Format(" > [{0},OnClose]", sender.ConnectionId));
                SetAppState(AppState.Stoped);
              
            }
            else
            {
                SetAppState(AppState.Stoped);
               
                // 出错了
                AddMsg(string.Format(" > [{0},OnError] -> OP:{1},CODE:{2}", sender.ConnectionId, enOperation, errorCode));
            }
            // 通知界面,只处理了连接错误,也没进行是不是连接错误的判断,所以有错误就会设置界面
            // 生产环境请自己控制
            return HandleResult.Ok;
        }
        public static void AddMsg(string str)
        {
            //Console.WriteLine(str);
            LogHelp.WriteeLog("", str);
        }


        #region TCP发送数据包
        private static bool SendTcpData(byte[] bs)
        {
            try
            {
                byte[] msgBody = bs.Skip(1).Take(bs.Length - 2).ToArray();
                byte[] bs1 = GwUtil.BuildTransferredRequest(msgBody);
                byte[] dataBuffers = new byte[bs1.Length + 2];
                dataBuffers[0] = 0x7E;
                Buffer.BlockCopy(bs1, 0, dataBuffers, 1, bs1.Length);
                dataBuffers[dataBuffers.Length - 1] = 0x7E;

                string deviceNo = GwUtil.BytesToHex(dataBuffers.Skip(5).Take(6).ToArray()).TrimStart('0');
                bool sdBool = client.Send(dataBuffers, dataBuffers.Length);
                LogHelp.WriteLog("ip:"+GovIP+"端口:"+GovPort +"数据:"+ GwUtil.BytesToHex(dataBuffers), "转发", deviceNo);
                //_networkStream.Write(dataBuffers, 0, dataBuffers.Length);

                //string keyStr = HandleData(bs);

                //byte[] msgID = bs.Skip(2).Take(2).ToArray();
                //string msgId = GwUtil.BytesToHex(msgID);

                //transDate td = new transDate();
                //td.ActiveTime = DateTime.Now;
                //td.sendBs = bs;
                //td.key = keyStr;
                //if (sdBool)
                //{

                //        lock (yjFs)
                //        {
                //            if (yjFs.ContainsKey(keyStr))
                //            {
                //                yjFs[keyStr] = td;
                //            }
                //            else
                //            {
                //                yjFs.Add(keyStr, td);

                //            }
                //        }


                //}

                //Console.WriteLine("发送到省平台服务器成功，长度 " + dataBuffers.Length);
                return sdBool;
            }
            catch (Exception e)
            {
                AddMsg(e.ToString());
                return false;
            }
        }
        private static bool SendTcpData1(byte[] bs)
        {
            try
            {
                byte[] msgBody = bs.Skip(1).Take(bs.Length - 2).ToArray();
                byte[] bs1 = GwUtil.BuildTransferredRequest(msgBody);
                byte[] dataBuffers = new byte[bs1.Length + 2];
                dataBuffers[0] = 0x7E;
                Buffer.BlockCopy(bs1, 0, dataBuffers, 1, bs1.Length);
                dataBuffers[dataBuffers.Length - 1] = 0x7E;
                bool sdBool = client.Send(dataBuffers, dataBuffers.Length);
                
              
                return sdBool;
            }
            catch (Exception e)
            {
                AddMsg(e.ToString());
                return false;
            }
        }
        private static string HandleData(byte[] bs)
        {
            //消息ID
            byte[] msgID = bs.Skip(2).Take(2).ToArray();
            string msgId = GwUtil.BytesToHex(msgID);

            //终端手机号
            byte[] bsPhoneNum = new byte[8];
            Buffer.BlockCopy(bs, 6, bsPhoneNum, 0, 8);
            string phoneNumber = GwUtil.BytesToHex(bsPhoneNum);

            //消息流水号
            byte[] bsSeqId = bs.Skip(14).Take(2).ToArray();

            string seqId = GwUtil.BytesToHex(bsSeqId);
            return msgId + "-" + phoneNumber + "-" + seqId;

        }
        #endregion

    
      
        #region 处理粘包问题

        private static void HandlePackages(byte[] buffers)
        {

            byte[] totalbuffers = null;
            var waitBuffers = _cacheBytes;

            if (waitBuffers != null && waitBuffers.Length > 0)
            {
                var waitLength = waitBuffers.Length;
                var receiveLength = buffers.Length;
                totalbuffers = new byte[receiveLength + waitLength];
                Buffer.BlockCopy(waitBuffers, 0, totalbuffers, 0, waitLength);
                Buffer.BlockCopy(buffers, 0, totalbuffers, waitLength, receiveLength);
            }
            else
            {
                totalbuffers = buffers;
            }

            //转义后：剩余包长度
            var remainLength = totalbuffers.Length;
            var readIndex = 0;

            //有些设备 7E未进行转义 重试一次
            var isTryed = false;

            int MessageheadLength = 15;

            // 剩余包 够一个完整包
            while (remainLength >= MessageheadLength)
            {
                if (!totalbuffers[readIndex].Equals(0x7E) /*|| !IsMsgIdOk(totalbuffers, readIndex)*/)
                {
                    LogHelp.WriteeLog("",string.Format( "剔除[readIndex = {0}],[value = {1}] ", readIndex, totalbuffers[readIndex]));

                    //剔除干扰数据
                    readIndex++;
                    remainLength--;
                    continue;
                }

                //消息体属性
                string property = GwUtil.ToBin16(totalbuffers, readIndex + 3, 16);
                //是否包含分包
                var subPackage = property[2] == '1';
                //消息体长度
                var bodyLength = Convert.ToInt32(property.Substring(6), 2);
                //数据包长度
                var dataLength = bodyLength + MessageheadLength + (subPackage ? 4 : 0);

                //剩余消息体不够一个完整包 退出
                if (dataLength > remainLength) break;

                //构造完整消息体
                var dataBuffers = new byte[dataLength];
                Buffer.BlockCopy(totalbuffers, readIndex, dataBuffers, 0, dataLength);

                //7E <-->7E 校验CRC
                if (dataBuffers.Last().Equals(0x7E)
                    && GwUtil.ValidateCheckCode(dataBuffers))
                {
                    //处理消息
                    //这里处理完，一个完整消息

                    // Console.WriteLine("接收数据：" + GwUtil.BytesToHex(dataBuffers));
                    //HandleOneExsunPackage(dataBuffers);
                    lock (_ydByteQ)
                    {
                        _ydByteQ.Enqueue(dataBuffers);
                    }
                    readIndex += dataLength;
                    remainLength -= dataLength;
                    isTryed = false;
                }
                else
                {
                    if (isTryed)
                    {
                        //LogHelper.Debug("isTryed[01]. {0},{1}", connection.ConnectionID, isTryed);
                        //已经重试过，重置
                        isTryed = false;
                        readIndex += dataLength;
                        remainLength -= dataLength;
                        LogHelp.WriteeLog("",string.Format("wrong. data={0}", GwUtil.BytesToHex(dataBuffers)));
                        break;
                    }
                    else
                    {
                        //LogHelper.Debug("isTryed[01]. {0},{1}", connection.ConnectionID, isTryed);
                        //未重试过，需要进行重试一次。
                        //校验码错误，有的设备没有正向7E转换
                        remainLength -= dataBuffers.Length;
                        var curlen = dataBuffers.Length;
                        while (GwUtil.ProcessTransferredRequest(dataBuffers).Length < dataLength)
                        {
                            if (remainLength > 0)
                            {
                                dataBuffers = new byte[curlen + 1];
                                Buffer.BlockCopy(totalbuffers, readIndex, dataBuffers, 0, dataBuffers.Length);
                                remainLength--;
                                curlen++;
                            }
                            else
                            {
                                break;
                            }
                        }
                        //LogHelper.Debug("ProcessTransferredRequest[02]. {0},{1}", connection.ConnectionID, FormatUtil.BytesToHexStr(dataBuffers));

                        dataBuffers = GwUtil.ProcessTransferredRequest(dataBuffers);
                        byte[] tmpBuffers = new byte[dataBuffers.Length + remainLength];
                        Buffer.BlockCopy(dataBuffers, 0, tmpBuffers, 0, dataBuffers.Length);
                        Buffer.BlockCopy(totalbuffers, totalbuffers.Length - remainLength, tmpBuffers,
                            dataBuffers.Length, remainLength);
                        totalbuffers = tmpBuffers;
                        remainLength = totalbuffers.Length;
                        readIndex = 0;
                        isTryed = true;
                        continue;
                    }
                }
            }

            //未处理完的数据包
            if (remainLength > 0)
            {
                var remainBuffers = new byte[remainLength];
                Buffer.BlockCopy(totalbuffers, readIndex, remainBuffers, 0, remainLength);
                //重设缓冲区
                _cacheBytes = remainBuffers;
                //rtCach.AddWaitBuffers(client.Handle.ToString(), remainBuffers);
            }
            else
            {
                //读完重设缓冲区 为空
                _cacheBytes = null;
                //rtCach.AddWaitBuffers(client.Handle.ToString(), null);
            }



        }

        #endregion

        #region 处理一个数据包
        private static void HandleOneExsunPackage(byte[] bs)
        {
            
            if (bs.First().Equals(0x7E) && bs.Last().Equals(0x7E) && GwUtil.ValidateCheckCode(bs))//
            {
                //消息ID
             
                int msgId = GwUtil.HexToInt(GwUtil.BytesToHex(bs.Skip(1).Take(2).ToArray()));
                //终端手机号
                byte[] bsPhoneNum = new byte[6];
                Buffer.BlockCopy(bs, 5, bsPhoneNum, 0, 6);
                string phoneNumber = GwUtil.BytesToHex(bsPhoneNum);
                //消息流水号
                byte[] bsSeqId = new byte[2];
                Buffer.BlockCopy(bs, 11, bsSeqId, 0, 2);
                int seqId = GwUtil.HexToInt(GwUtil.BytesToHex(bsSeqId));
                //消息体属性
                string property = GwUtil.ToBin16(bs, 3, 16);
                //加密标志
                int encry = property[5] == '1' ? 1 : 0;
                //多媒体标识
                bool multiMedia = property[0] == '1';
                //数据是否分包
                bool subPackage = property[2] == '1';
                //消息体长度
                int bodyLength = Convert.ToInt32(property.Substring(6), 2);
                byte[] bodyBuffer = new byte[bodyLength];
                ushort totalPacket = 0;
                ushort curPacket = 0;
                if (subPackage)
                {
                    //总包数
                    totalPacket = (UInt16)GwUtil.ToInt16(bs, 13);
                    //当前包数目
                    curPacket = (UInt16)GwUtil.ToInt16(bs, 15);
                    Buffer.BlockCopy(bs, 17, bodyBuffer, 0, bodyLength);
                }
                else
                {
                    Buffer.BlockCopy(bs, 13, bodyBuffer, 0, bodyLength);
                }

                if (msgId == 0x8001)
                {
                    StringBuilder RecBStr = new StringBuilder();
                    byte[] reposeArr = bodyBuffer.Skip(0).Take(2).ToArray();
                    byte[] resultArr = bodyBuffer.Skip(2).Take(2).ToArray();
                
                    int result = (int)bodyBuffer[4];
                    string reStr = string.Empty;
                    switch (result)
                    {
                        case 0: reStr = "成功/确认"; break;
                        case 1: reStr = "失败"; break;
                        case 2: reStr = "消息有误"; break;
                        case 3: reStr = "不支持"; break;
                    }
                    RecBStr.Append("手机号：" + phoneNumber + "应答流水号: " + GwUtil.BytesToHex(reposeArr) + "应答ID: " + GwUtil.BytesToHex(resultArr) + "结果: " + reStr);
                    //AddMsg(RecBStr.ToString());
                   
                }
            }
            else
            {
                AddMsg("校验码错误:" + GwUtil.BytesToHex(bs));
               
            }
        }

        #endregion

    }

}
